/* 
Copyright Paul James Mutton, 2001-2007, http://www.jibble.org/

This file is part of PircBot.

This software is dual-licensed, allowing you to choose between the GNU
General Public License (GPL) and the www.jibble.org Commercial License.
Since the GPL may be too restrictive for use in a proprietary application,
a commercial license is also provided. Full license information can be
found at http://www.jibble.org/licenses/

 */

package org.jibble.pircbot;

import java.util.StringTokenizer;
import java.util.Vector;

/**
 * This class is used to process DCC events from the server.
 * 
 * @since 1.2.0
 * @author Paul James Mutton, <a
 *         href="http://www.jibble.org/">http://www.jibble.org/</a>
 * @version 1.4.6 (Build time: Wed Apr 11 19:20:59 2007)
 */
public class DccManager {

	private PircBot _bot;

	private Vector<DccFileTransfer> _awaitingResume = new Vector<DccFileTransfer>();

	/**
	 * Constructs a DccManager to look after all DCC SEND and CHAT events.
	 * 
	 * @param bot
	 *            The PircBot whose DCC events this class will handle.
	 */
	DccManager(PircBot bot) {
		_bot = bot;
	}

	/**
	 * Add this DccFileTransfer to the list of those awaiting possible resuming.
	 * 
	 * @param transfer
	 *            the DccFileTransfer that may be resumed.
	 */
	void addAwaitingResume(DccFileTransfer transfer) {
		synchronized (_awaitingResume) {
			_awaitingResume.addElement(transfer);
		}
	}

	/**
	 * Processes a DCC request.
	 * 
	 * @return True if the type of request was handled successfully.
	 */
	boolean processRequest(String nick, String login, String hostname,
			String request) {
		StringTokenizer tokenizer = new StringTokenizer(request);
		tokenizer.nextToken();
		String type = tokenizer.nextToken();
		String filename = tokenizer.nextToken();

		if (type.equals("SEND")) {
			long address = Long.parseLong(tokenizer.nextToken());
			int port = Integer.parseInt(tokenizer.nextToken());
			long size = -1;
			try {
				size = Long.parseLong(tokenizer.nextToken());
			} catch (Exception e) {
				// Stick with the old value.
			}

			DccFileTransfer transfer = new DccFileTransfer(_bot, this, nick,
					login, hostname, type, filename, address, port, size);
			_bot.onIncomingFileTransfer(transfer);

		} else if (type.equals("RESUME")) {
			int port = Integer.parseInt(tokenizer.nextToken());
			long progress = Long.parseLong(tokenizer.nextToken());

			DccFileTransfer transfer = null;
			synchronized (_awaitingResume) {
				for (int i = 0; i < _awaitingResume.size(); i++) {
					transfer = _awaitingResume.elementAt(i);
					if (transfer.getNick().equals(nick)
							&& transfer.getPort() == port) {
						_awaitingResume.removeElementAt(i);
						break;
					}
				}
			}

			if (transfer != null) {
				transfer.setProgress(progress);
				_bot.sendCTCPCommand(nick, "DCC ACCEPT file.ext " + port + " "
						+ progress);
			}

		} else if (type.equals("ACCEPT")) {
			int port = Integer.parseInt(tokenizer.nextToken());
			// long progress = Long.parseLong(tokenizer.nextToken());

			DccFileTransfer transfer = null;
			synchronized (_awaitingResume) {
				for (int i = 0; i < _awaitingResume.size(); i++) {
					transfer = _awaitingResume.elementAt(i);
					if (transfer.getNick().equals(nick)
							&& transfer.getPort() == port) {
						_awaitingResume.removeElementAt(i);
						break;
					}
				}
			}

			if (transfer != null) {
				transfer.doReceive(transfer.getFile(), true);
			}

		} else if (type.equals("CHAT")) {
			long address = Long.parseLong(tokenizer.nextToken());
			int port = Integer.parseInt(tokenizer.nextToken());

			final DccChat chat = new DccChat(_bot, nick, login, hostname,
					address, port);

			new Thread() {
				@Override
				public void run() {
					_bot.onIncomingChatRequest(chat);
				}
			}.start();
		} else {
			return false;
		}

		return true;
	}

	/**
	 * Remove this transfer from the list of those awaiting resuming.
	 */
	void removeAwaitingResume(DccFileTransfer transfer) {
		_awaitingResume.removeElement(transfer);
	}

}
